#include"compressTitle_cpu.h"

#define NUM (1)
#define SIGN (0)
#define LETTER (2)


bool isLetter(char c) {
        if( c >= 'a' && c <= 'z')
                return true;
        if( c >= 'A' && c <= 'Z')
                return true;
        return false;
}

bool isNum(char c) {
        if(c >= '0' && c<= '9')
                return true;
        return false;
}

bool isZero(char c) {
        return c == '0';
}


int getTitleFormat(char* title, uint8** format)
{
        int titleLen = strlen(title);
        int i, formatOffset = 0;

        (*format) = (uint8*)malloc(titleLen);
        for(i=0; i<titleLen; i++) {
                if(isLetter(title[i]))
                        (*format)[i] = LETTER;
                else if(isNum(title[i])){
                        if(isZero(title[i]) && ( i==0 || (*format)[i-1] != NUM))
                                (*format)[i] = SIGN;
                        else
                                (*format)[i] = NUM;
                }
                else
                        (*format)[i] = SIGN;
        }
		for(i=0; i<titleLen-1; i++){
			if((*format)[i] == LETTER && (*format)[i+1] != LETTER) {
					(*format)[formatOffset++] = LETTER;
			}
			else if((*format)[i] == NUM && (*format)[i+1] != NUM) {
					(*format)[formatOffset++] = NUM;
			}
			else if((*format)[i] == SIGN){
				(*format)[formatOffset++] = SIGN;
			}
		}
		(*format)[formatOffset++] = (*format)[titleLen - 1];
		return formatOffset;
}

void parseTitle(char* titleLine,uint8* strMap, uint32* mapSize, uint32* strBuffer, uint32* intBuffer, 
				uint8* signBuffer, uint8* format, int formatLen, int titleId,
				uint32 strBufferWidth, uint32 numBufferWidth, uint32 signBufferWidth)
{
	int i,formatOffset=0, offset;
	uint32 intCount=0, strCount=0, signCount=0;

	uint32 num;
	char str[MAX_STR_LEN];
	for(i=0; titleLine[i] !='\0'; i++) {
		if(format[formatOffset] == LETTER) {
			offset = 0;
			while(titleLine[i] != '\0' && isLetter(titleLine[i]))
				str[offset++] = titleLine[i++];
			str[offset] = '\0';
			strBuffer[strBufferWidth * strCount + titleId] = dictCompress(strMap, mapSize, str);
			strCount++;
			i--;
			formatOffset++;
		}
		else if(format[formatOffset] == NUM) {
			num = 0;
			while(titleLine[i] != '\0' && isNum(titleLine[i])) { 
				num = num * 10 + (titleLine[i] - '0');
				i++;	
			}
			intBuffer[numBufferWidth * intCount + titleId] = num;
			intCount++;
			i--;
			formatOffset++;
		}
		else if(format[formatOffset] == SIGN){
			signBuffer[signBufferWidth * signCount + titleId] = titleLine[i];
			signCount++;
			formatOffset++;
		}
	}
}

void compressTitle(char* titleBuffer, uint32 titleCount, FILE* outputFile, uint32* compressedTitleSize )
{
	uint32 i,j,k=0;
	uint8* format;
	
	uint32 strCount=0, signCount=0, numCount=0, formatLen=0;
	char title[MAX_TITLE_LEN];
	const int distinctStrCount = 100;
	uint8 strMap[distinctStrCount * MAX_STR_LEN];
	uint32 mapSize = 0;

	uint32 strBufferOffset = 0, numBufferOffset = 0, signBufferOffset = 0;
	for(i=0; titleBuffer[k] != '\0'; i++)
		title[i] = titleBuffer[k++];
	title[i] = '\0';
	k++;

	formatLen = getTitleFormat(title, &format);

	for(i=0; i<formatLen; i++){
		if(format[i] == LETTER) {
			strCount++;
		}
		else if(format[i] == NUM){
			numCount++;
		}
		else if(format[i] == SIGN){
			signCount++;
		}
	}

	uint32* strBuffer = (uint32*)malloc(titleCount * sizeof(int) * strCount);
	uint32* numBuffer = (uint32*)malloc(titleCount * sizeof(int) * numCount);
	uint8* signBuffer = (uint8*)malloc(titleCount * signCount);

	strBufferOffset = titleCount * strCount;
	signBufferOffset = titleCount * signCount;
	numBufferOffset = titleCount * numCount;
	parseTitle(title,strMap,&mapSize, strBuffer, numBuffer, signBuffer, 
				format, formatLen, 0, titleCount, titleCount, titleCount);
	for(i=1; i<titleCount; i++) {
		
		for(j=0; j<MAX_TITLE_LEN; j++) {
			title[j] = titleBuffer[k++];
			if(title[j] == '\0')
				break;
		}
		parseTitle(title,strMap,&mapSize, strBuffer, numBuffer, signBuffer, 
					format, formatLen, i, titleCount, titleCount, titleCount);
	}
	
	int compressedSize = 1000000;
	uint32 c_strBufferOffset = 0, c_numBufferOffset = 0, c_signBufferOffset = 0;

	uint32* comp_strBuffer = (uint32*)malloc(compressedSize);
	uint32* comp_numBuffer = (uint32*)malloc(compressedSize*50);
	uint8* comp_signBuffer = (uint8*)malloc(compressedSize*50);
	uint32* comp_strBuffer_len = (uint32*)malloc(compressedSize);
	uint32* comp_numBuffer_len = (uint32*)malloc(compressedSize*50);
	uint32* comp_signBuffer_len = (uint32*)malloc(compressedSize*50);
	
	printf("title buffer before rle compress: %u\n", (strBufferOffset + numBufferOffset) * sizeof(int) + signBufferOffset);

	cpu_delta_compress((int*)numBuffer,titleCount,numCount);

	cpu_RLE(strBuffer, strBufferOffset, comp_strBuffer,  comp_strBuffer_len, &c_strBufferOffset);
	cpu_RLE(numBuffer, numBufferOffset, comp_numBuffer,  comp_numBuffer_len, &c_numBufferOffset);
	cpu_RLE(signBuffer, signBufferOffset, comp_signBuffer,  comp_signBuffer_len, &c_signBufferOffset);

//	fwrite(&titleCount, sizeof(int), 1, outputFile);
	fwrite(&formatLen, sizeof(int), 1, outputFile);
	fwrite(format, 1, formatLen, outputFile);
	fwrite(&mapSize, sizeof(int),1, outputFile);
	fwrite(strMap, sizeof(char), MAX_STR_LEN * mapSize, outputFile);
	fwrite(&c_strBufferOffset, sizeof(int),1, outputFile);
	fwrite(comp_strBuffer, sizeof(int), c_strBufferOffset, outputFile);
	fwrite(comp_strBuffer_len, sizeof(int), c_strBufferOffset, outputFile);
	fwrite(&c_numBufferOffset, sizeof(int),1, outputFile);
	fwrite(comp_numBuffer, sizeof(int), c_numBufferOffset, outputFile);
	fwrite(comp_numBuffer_len, sizeof(int), c_numBufferOffset, outputFile);
	fwrite(&c_signBufferOffset, sizeof(int),1, outputFile);
	fwrite(comp_signBuffer, sizeof(char), c_signBufferOffset, outputFile);
	fwrite(comp_signBuffer_len, sizeof(int), c_signBufferOffset, outputFile);

	(*compressedTitleSize) = (c_strBufferOffset + c_numBufferOffset) * 2 * sizeof(int) + c_signBufferOffset * 10;
	printf("title buffer size after compress: %u\n",(c_strBufferOffset + c_numBufferOffset) * 2 * sizeof(int) + c_signBufferOffset * 10);

	free(comp_signBuffer);
	free(comp_strBuffer);
	free(comp_numBuffer);
	free(comp_strBuffer_len);
	free(comp_numBuffer_len);
	free(comp_signBuffer_len);
	free(strBuffer);
	free(numBuffer);
	free(signBuffer);
}


void decompressTitle(FILE* fin, char* titleBuffer, const int titleCount, const int max_title_len)
{
	uint32 mapSize;
	uint32 i,j,l,k=0;
	uint8* format;
	uint32 formatLen=0;
	uint32 strCount=0, signCount=0, numCount=0;
	const int distinctStrCount = 100;
	uint8 strMap[distinctStrCount * MAX_STR_LEN];
	int formatOffset = 0;
	int compressedSize = 1000000;
	uint32 c_strBufferOffset = 0, c_numBufferOffset = 0, c_signBufferOffset = 0;

	fread(&formatLen, sizeof(int), 1, fin);
	format = (uint8*)malloc(formatLen);
	fread(format, 1, formatLen, fin);

	fread(&mapSize, sizeof(int), 1, fin);
	fread(strMap, sizeof(char), MAX_STR_LEN*mapSize, fin);
	
	fread(&c_strBufferOffset, sizeof(int),1, fin);
	uint32* comp_strBuffer = (uint32*)malloc(c_strBufferOffset * sizeof(int));
	uint32* comp_strBuffer_len = (uint32*)malloc(c_strBufferOffset * sizeof(int));
	fread(comp_strBuffer, sizeof(int), c_strBufferOffset, fin);
	fread(comp_strBuffer_len, sizeof(int), c_strBufferOffset, fin);

	fread(&c_numBufferOffset, sizeof(int),1, fin);
	uint32* comp_numBuffer = (uint32*)malloc(c_numBufferOffset * sizeof(int));
	uint32* comp_numBuffer_len = (uint32*)malloc(c_numBufferOffset * sizeof(int));
	fread(comp_numBuffer, sizeof(int), c_numBufferOffset, fin);
	fread(comp_numBuffer_len, sizeof(int), c_numBufferOffset, fin);

	fread(&c_signBufferOffset, sizeof(int),1, fin);
	uint8* comp_signBuffer = (uint8*)malloc(c_signBufferOffset);
	uint32* comp_signBuffer_len = (uint32*)malloc(c_signBufferOffset * sizeof(int));
	fread(comp_signBuffer, sizeof(char), c_signBufferOffset, fin);
	fread(comp_signBuffer_len, sizeof(int), c_signBufferOffset, fin);

	for(i=0; i<formatLen; i++){
		if(format[i] == LETTER) {
			strCount++;
		}
		else if(format[i] == NUM){
			numCount++;
		}
		else if(format[i] == SIGN){
			signCount++;
		}
	}

	uint32* strBuffer = (uint32*)malloc(titleCount * sizeof(int) * strCount);
	uint32* numBuffer = (uint32*)malloc(titleCount * sizeof(int) * numCount);
	uint8* signBuffer = (uint8*)malloc(titleCount * signCount);

	cpu_RLE_decompression(comp_strBuffer, comp_strBuffer_len, c_strBufferOffset, strBuffer); 
	cpu_RLE_decompression(comp_numBuffer, comp_numBuffer_len, c_numBufferOffset, numBuffer); 
	cpu_RLE_decompression(comp_signBuffer, comp_signBuffer_len, c_signBufferOffset, signBuffer); 
	cpu_delta_decompress((int*)numBuffer, titleCount, numCount);

	k = 0;
	char tempStr[MAX_STR_LEN];
	char tempNum[MAX_STR_LEN];
	for(i=0; i<titleCount; i++) {
		strCount = 0;
		numCount = 0;
		signCount = 0;
		k = 0;
		for(j=0; j<formatLen; j++) {
			if(format[j] == LETTER){
				dictDecompress(strMap, strBuffer[strCount * titleCount + i], tempStr);
				strCount++;
				for(l=0; tempStr[l] != '\0'; l++) {
					titleBuffer[k++] = tempStr[l];			
				}
			}
			else if(format[j] == NUM) {
				uint32 num = numBuffer[numCount * titleCount + i];
				numCount++;
				l=0;
				while(num!=0) {
					tempNum[l++] = (num % 10) + '0';
					num = num / 10;
				}
				while(l>0){ 
					l--;
					titleBuffer[k++] = tempNum[l];
				}
			}
			else if(format[j] == SIGN) {
				titleBuffer[k++] = signBuffer[signCount * titleCount + i];
				signCount++;
			}
		}
		titleBuffer[k++] = '\0';
		titleBuffer += max_title_len;
	}

	free(comp_strBuffer);
	free(comp_numBuffer);
	free(comp_signBuffer);
	free(comp_strBuffer_len);
	free(comp_numBuffer_len);
	free(comp_signBuffer_len);
	free(strBuffer);
	free(numBuffer);
	free(signBuffer);
}
/*
int main()
{
	char* fileName = "titleBuffer";
	char* outFileName = "compressedTitleBuffer";
	FILE* infile = fopen(fileName,"r");
	if(infile == NULL)
		printf("cant open %s", fileName);
	FILE* outfile = fopen(outFileName, "w");
	
	uint32 bufferSize;
	fseek(infile, 0L, SEEK_END);

   	bufferSize = ftell(infile);

   	rewind(infile);
	char* titleBuffer = (char*)malloc(bufferSize);
	fread(titleBuffer, 1, bufferSize, infile);
	compressTitle(titleBuffer, 1000000, outfile );
	fclose(infile);
	fclose(outfile);
	printf("compress finished\n");
//	char* titleBuffer = (char*)malloc(bufferSize);
	FILE *inDecompressFile = fopen(outFileName, "r");
	decompressTitle(inDecompressFile, titleBuffer);
	FILE *outFile2 = fopen("decompressedTitleBuffer","w");
	fwrite(titleBuffer,1, bufferSize, outFile2);
	fclose(inDecompressFile);
	fclose(outFile2);
}

*/
